ICS3U: Introduction to Computer Science, Grade 11, University Preparation
Recall: A method consists of:
The general form of a method is:
<optional_modifiers> <return_type> <name>(<parameters>) { <statements> }
int interest = calculateInterest(amount, rate);
int term = coefficient * power(base, exponent); if (nextValue() == 4) { ... }
Console.print("Score: " + calculateScore());
String nameInCaps = getName().toUppercase();
Below is a modification of the showSum(int, int, int) example above, which returns the sum, so main method can output it to the console.
package activity3; import simpleIO.Console; public class MethodsExample { public static void main(String[] args) { int total = calcSum(2, 3, 10); Console.print("The sum is " + total); } public static int calcSum(int a, int b, int c) { int sum = a + b + c; return sum; } }
In this version of the program, the result of the addition statement is returned to the main method, and assigned to the variable total.
![]() |
Parameters and return statements are like a one-way-street. Information flows either to the method (parameters), or back to the code that called the method (return statement) |
---|
The example below shows a method cubeOf(double), which returns the cube of its parameter
Try running this code in Eclipse.
package activity3; import simpleIO.Console; public class CubeCalculator { public static void main(String[] args) { double num, cube; // Input num = Console.readDouble("Enter a number:"); // Processing cube = cubeOf(num); // Output Console.print("The cube of " + num + " is " + cube); } public static double cubeOf(double x) { double cube; cube = x * x * x; return cube; } }
Notice this example includes two methods that return values - the Console.readDouble(String) as well as cubeOf(double). Since cubeOf is defined inside the same class as the method call, you do not need to include the class name. However, the readDouble() method is located inside the Console class, so you must include its class name for the method call to work.
In the previous activity, we created methods that printed directly to the Console. Our goal for this activity is to limit calls to Console from methods and use the Console class only in the main method. One way to do this is to have our methods return a String, and then this value is printed to the Console.
Below is an example of a modified RightTriangle application from the previous activity. Notice that now the method returns a String instead of using Console.print().
package activity3; import simpleIO.Console; public class RightTriangle { public static void main(String[] args) { int triangleSize = Console.readInt("Enter a size for your triangle: "); /* draw a right triangle with base size entered by user */ for (int i = 1; i <= triangleSize; i++) { Console.print(createBar(i)); //parameter: i } } public static String createBar(int length) { //argument: length String triangle = ""; for (int i = 0; i < length; i++) { triangle += "* "; } return triangle; } }
One final note about terminology: Methods that return a value are also called functions.
It is important that a programmer validate his/her program using a full range of test cases before it is implemented. This means that when you are testing your program you should try and see how it will react to a variety of input values and ensure that the results you receive are correct. When creating test cases, you should include both regular inputs, as well as inputs that might cause potential problems in the program.
To manually test a program can be very time consuming, so it can be helpful to use an automated testing strategy to simplify the process. In this activity we will be learning about the JUnit automated testing framework that is integrated into the Eclipse IDE.
In order for automated testing to be useful, you must use functions in your programs. The JUnit framework is used for testing methods, but it is not meant for testing the main() method. Recall the general model for designing computer programs: Input - Processing - Storage - Output. Ideally, your methods will contain the Processing portion of your program, while the main method, using the Console or Dialog class, will handle the Input & Output. This setup will allow you to make use of automated testing.
Considering the RectangleArea program from Unit 2, Activity 3. You can refactor it to do the processing portion in a method:
Select the code that you wish to place in a method.
Give your method a name, give it the PUBLIC access, and check that the parameters are correct
Eclipse will create the method and replace the code with a method call
Now your method is ready to be tested using JUnit!
To create an automated test, follow these steps:
Once your JUnit Class is created, you will need to populate it with test cases. For each test case, you must decide what input you will use, as well as the output that you expect to receive. Then call the assertEquals(expected, actual) method provided by the JUnit framework.
The following is a simple automated test for the RectangleArea class. Notice that each test scenario (normal behaviour, one input is zero, one input is negative) is placed in its own method, with one or more test cases per method. Also the annotation "@Test" must be placed prior to each method so JUnit knows how to run it correctly.
package activity3; import static org.junit.Assert.*; import org.junit.Test; public class RectangleAreaTest { @Test public void testNormalScenario() { assertEquals(25, RectangleArea.calculateArea(5, 5)); assertEquals(42, RectangleArea.calculateArea(6, 7)); } @Test public void testZeroValues() { assertEquals(0, RectangleArea.calculateArea(0, 5)); assertEquals(0, RectangleArea.calculateArea(5, 0)); } @Test public void testNegativeValues() { assertEquals(-1, RectangleArea.calculateArea(-5, 5)); } }
When you run a JUnit Test, the results are shown in the JUnit View, usually in the same location as the Console View.
When the test above is run, the third scenario fails, since we have not done any checking for negative inputs. This failed test would be recorded as a bug that needs to be fixed.
There are multiple version of the assertEquals() method provided by the JUnit framework, so you will use the one that is appropriate to the method that you are testing.
For example, you could test the createBar() method in the RightTriangle application like this:
@Test public void testCreateBar() { assertEquals("* * * * * * ", RightTriangle.createBar(6)); assertEquals("* * ", RightTriangle.createBar(2)); }
You could test the cubeOf() method in the CubeCalculator application like this:
@Test public void testCube() { assertEquals(125.0, CubeCalculator.cubeOf(5.0), 0.5); assertEquals(1.728, CubeCalculator.cubeOf(1.2), 0.0005); }
![]() |
Why is the extra parameter needed when testing methods that return doubles? This is due to the lack of precision in storing double variables, which you may have already noticed in some of your programs. Usually, the delta argument is a small number that represents the allowable rounding error. For example, suppose we had a method called calculatePay(int hours, double rate) in an Employee class, which accepts the number of hours worked and the hourly rate, and returns the total pay. The assert statement to test that method could be: assertEquals(112.50, Employee.calculatePay(15, 7.50), 0.005); This delta value of 0.005 would allow for rounding (up or down) to the nearest hundredth (2 decimal places of accuracy). |
---|
When creating your tests, consider the following suggestions:
![]() |
To learn more about JUnit and automated testing, read the JUnit API |
---|
Finally, it's important to realize that not all programs can be testing only with automated tests (there will still be a need for some manual testing!), but they are a great asset for designing robust programs. Many programmers adopt a "test-driven development" programming style, where the programmer creates their automated tests before creating their programs. That way they know when their program is complete; it passes all the test cases!
To access the results of your automated tests, visit your repository on GitHub.com and select "Actions". This will allow you to view the results of the autograding tests that I have created.
Reading and interpreting the results can be tricky, so I've created a short video to show some common types of results.
Below are some images of what the output of the autograding tests could look like:
If the method exists, but is not implemented correctly, you will get a FAILED message. Pay close attention to these; they indicate that there is a logic error in your code. Return to your code, review the requirements, or ask your teacher to help you diagnose the problem. |
![]() |
---|
![]() |
If a class or method is missing, you will get an ERROR. If you have named a class or a method incorrectly, you will get an error as well. Please ensure that your class names and method names are exactly as specified in the practice exercises. It is normal to see many of these messages at the start of the unit. They should go away as you implement the required classes and methods |
---|
If everything works perfectly, you should see a BUILD SUCCESSFUL message and the activity title with a green checkmark. Each batch of tests is run for an entire activity. You will not see this message until all tests for a particular activity have passed. |
![]() |
---|
Once you have read the material above complete the following activities. Place all your classes in the activity3 package. Use the names in bold as your class name / method name for each program!
public static void main(String[] args) { //Display numbers 1 through 10 in Spanish for (int i = 1; i <= 10; i++) { String spanishNumber = translate(i); Console.print(i + " in spanish is " + spanishNumber); } }
Visit GitHub Actions and verify that the junit tests executed properly
Commit your progress to GitHub every day. Submit the link on the Hapara evidence card when you are finished.